﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;

namespace ArrowVersionUpdater
{
    /// <summary>
    /// This app takes in a list of Arrow content files where the version has to be updated manually, and it swaps in the current Arrow version
    /// from the version.cs file.
    /// </summary>
    public class ArrowVersionUpdater
    {
        public static void Main(string[] args)
        {
            try
            {
                // check num args
                if (args.Length != 3)
                {
                    string sBadArgs = "Incorrect number of arguments.\nUsage: updateArrowVersions version.cs files.xml outDir";
                    Console.Error.WriteLine(sBadArgs);
                    return;
                }

                // version.cs
                string versionFilePath = args[0];
                if (string.IsNullOrEmpty(versionFilePath))
                {
                    string sBadArgs = "Invalid version file name. Name cannot be empty.";
                    Console.Error.WriteLine(sBadArgs);
                    return;
                }

                // verify file list parameter
                string arrowFileList = args[1];
                if (string.IsNullOrEmpty(arrowFileList))
                {
                    string sBadArgs = "Invalid file list name. Name cannot be empty.";
                    Console.Error.WriteLine(sBadArgs);
                    return;
                }

                // verify the output directory parameter
                string outDir = args[2];
                if (string.IsNullOrEmpty(outDir))
                {
                    string sBadArgs = "Invalid output directory name. Name cannot be empty.";
                    Console.Error.WriteLine(sBadArgs);
                    return;
                }
                Directory.CreateDirectory(outDir);

                // get the arrow version number
                string versionFile = File.ReadAllText(versionFilePath);
                int idInd = versionFile.IndexOf("ARROW_MAJOR_VERSION_STR");
                int eqInd = versionFile.IndexOf('=', idInd);
                int colInd = versionFile.IndexOf(';', eqInd);
                int len = colInd - eqInd - 1;
                string arrowAssemblyVersion = versionFile.Substring(eqInd + 1, len).Trim().Replace("\"", string.Empty);

                // get the kailua version number
                idInd = versionFile.IndexOf("KAILUA_VERSION_STR");
                eqInd = versionFile.IndexOf('=', idInd);
                colInd = versionFile.IndexOf(';', eqInd);
                len = colInd - eqInd - 1;
                string kailuaAssemblyVersion = versionFile.Substring(eqInd + 1, len).Trim().Replace("\"", string.Empty);

                // load the version dependent content files list
                XmlDocument fileListXml = new XmlDocument();
                fileListXml.Load(arrowFileList);

                // go through each version dependent content file
                int nodeNum = 0;
                List<string> errors = new List<string>();
                foreach (XmlNode ndFile in fileListXml.SelectNodes("/files/file"))
                {
                    // get the file name
                    XmlNode ndfilePath = ndFile.SelectSingleNode("path");
                    if (ndfilePath == null)
                    {
                        // note missing file name and continue
                        string sBadFileNode = string.Format("File entry #{0} missing path node.\nActual XML:\n{1}", nodeNum, ndFile.OuterXml);
                        errors.Add(sBadFileNode);
                        continue;
                    }
                    string filePath = ndfilePath.InnerText;
                    if (string.IsNullOrEmpty(filePath))
                    {
                        // note empty file name and continue
                        string sBadFileNode = string.Format("File entry #{0} path node empty.\nActual XML:\n{1}", nodeNum, ndFile.OuterXml);
                        errors.Add(sBadFileNode);
                        continue;
                    }

                    // get the file text
                    string fileText = File.ReadAllText(filePath);

                    // swap in the version numbers
                    string versionPlaceHolder = "#ARROW_MAJOR_VERSION_STR";
                    fileText = fileText.Replace(versionPlaceHolder, arrowAssemblyVersion);
                    versionPlaceHolder = "#KAILUA_VERSION_STR";
                    fileText = fileText.Replace(versionPlaceHolder, kailuaAssemblyVersion);

                    // write the versioned file out to the output directory
                    string fileName = filePath.Substring(filePath.LastIndexOf('\\') + 1);
                    string fileOutFullPath = string.Format("{0}\\{1}", outDir, fileName);
                    File.WriteAllText(fileOutFullPath, fileText);

                    nodeNum++;
                }

                // print the errors
                if (errors.Count > 0)
                {
                    foreach (string error in errors)
                        Console.Error.WriteLine(error);
                    Console.Error.WriteLine("There were errors in the file list, {0}.", arrowFileList);
                    return;
                }

                // print finish message
                Console.WriteLine("Versions substituted into files in {0}.", outDir);
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("There was an error updating the version content files.\n\n{0}\n\nIn: {1}\n\nAt: {2}", ex.Message, ex.Source, ex.StackTrace);
            }
        }
    }
}
